package com.nulldev.util.io.legacy.cstreams;

import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class CoderThread extends Thread {
	private final PipedInputStream inSink;

	private final PipedOutputStream outSink;

	private final Runnable workhorse;

	private Throwable throwable;

	public CoderThread(final Coder coder, final InputStream in) throws IOException {
		this.inSink = new PipedInputStream();
		this.outSink = new PipedOutputStream(inSink);
		this.workhorse = new Runnable() {
			public void run() {
				try {
					coder.code(in, outSink);

					flush(outSink);
				} catch (Throwable e) {
					throwable = e;
				} finally {
					close(outSink);
				}
			}
		};
	}

	public CoderThread(final Coder coder, final OutputStream out) throws IOException {
		this.outSink = new PipedOutputStream();
		this.inSink = new PipedInputStream(outSink);
		this.workhorse = new Runnable() {
			public void run() {
				try {
					coder.code(inSink, out);

					flush(out);
				} catch (Throwable e) {
					throwable = e;
				} finally {
					close(inSink);
				}
			}
		};
	}

	public void run() {
		workhorse.run();
	}

// ==

	public Throwable getThrowable() {
		return throwable;
	}

	public void checkForException() throws IOException {
		if (null != throwable) {
			if (throwable instanceof IOException) {
				throw (IOException) throwable;
			} else {
				throw new IOException(throwable);
			}
		}
	}

	public PipedInputStream getInputStreamSink() {
		return inSink;
	}

	public PipedOutputStream getOutputStreamSink() {
		return outSink;
	}

// ==

	protected boolean flush(Flushable flushable) {
		if (flushable != null) {
			try {
				flushable.flush();

				return true;
			} catch (IOException e) {
				// mute
			}
		}

		return false;
	}

	protected boolean close(Closeable closeable) {
		if (closeable != null) {
			try {
				closeable.close();

				return true;
			} catch (IOException e) {
				// mute
			}
		}

		return false;
	}
}
